/*****************************************************************************
 * $Workfile:: fet.c                                                         $
 * $Revision:: 19                                                           $
 * $JustDate::  3/21/12                                               $
 *
 *      GENIE V ECU
 *      FET Interface
 *****************************************************************************/

#include "main.h"
#include "fet.h"
#include "nvm.h"
#include "faults.h"
#include "switches.h"
#include "control.h"
#include "load_sensing.h"
#include "alarm.h"

#define FET_CHECK_CYCLE     SYSTEM_CYCLE

Fet_t Fets;
unsigned int DriveCurrent;

static const struct Check
{
   UINT8  bErrorCode;
   UINT16 wMask;
    UINT8 (*pfSSRStatus)(void);
} FET_CheckTable[ ] =
{
     // err code          wMask         check function
     {FAULT_FORWARD_COIL, FET_FORWARD,  u8GetSSRStatus6C7A }
    ,{FAULT_REVERSE_COIL, FET_REVERSE,  u8GetSSRStatus6C7A }
    ,{FAULT_UP_COIL,      FET_UP,       u8GetSSRStatus6A6B }
    ,{FAULT_DOWN_COIL,    FET_DOWN,     u8GetSSRStatus6A6B }
    ,{FAULT_RIGHT_COIL,   FET_RIGHT,    u8GetSSRStatus7B7C }
    ,{FAULT_LEFT_COIL,    FET_LEFT,     u8GetSSRStatus7B7C }
    ,{FAULT_BRAKE_COIL,   FET_BRAKES,   u8GetSSRStatus2A9C   }
};

#define SOLENOID_CURRENT    3   // adc channel
#define NUMBER_OF_FETS_TO_CHECK ( sizeof( FET_CheckTable) / sizeof( const struct Check) )
static struct
{
   UINT8  bOffStatus[ NUMBER_OF_FETS_TO_CHECK];
   UINT8  bErrorCount[ NUMBER_OF_FETS_TO_CHECK];
   UINT8  u8DualOpenStatus[ NUMBER_OF_FETS_TO_CHECK];
   UINT8  bFetToCheck;
   UINT8  bCoilFaultDetectionPeriod;
   UINT8  bErrorCountBrake;
} FET_Data;

#define ERROR_LATCH  ( FET_Data.bCoilFaultDetectionPeriod )

/*******************************************************************************
 *
 * PROCEDURE:  FET_Setup()
 *
 * DESCRIPTION: It converts the fet fault detection time.
 *              It is called once on NVM parameters initialization.
 *
 *
 * VARIABLE NAME  R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 * FetsLocal        R/W
 * Fets             R
 ******************************************************************************/

void
FET_Setup(void)
{
   //
   // the NVM parameters must be converted to the number of the FET_CHECK_CYCLEs.
   //
   FET_Data.bCoilFaultDetectionPeriod =
      ((((UINT32)lift_setup.bCoilFaultDetectionPeriod)
        * (COIL_FAULT_DETECTION_PERIOD_TO_COUNT / FET_CHECK_CYCLE))
       / NUMBER_OF_FETS_TO_CHECK);

}

/*******************************************************************************
 *
 * PROCEDURE:  FET_Update()
 *
 * DESCRIPTION: It will shift the FET to thefet register..
 *              requirement and so on. It is mainly called every one millisecond
 *              to overcome probable noise. I was found that any errors
 *              shorter than 4 millisecond doesn;t effect a lift operations.
 *
 * VARIABLE NAME  R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 * FetsLocal        R/W
 * Fets             R
 ******************************************************************************/

void
FET_Update(void)
{
   vSetDuty7A((Fets.word & FET_FORWARD) ? 100 : 0);
   vSetDuty6C((Fets.word & FET_REVERSE) ? 100 : 0);
   vSetDuty6A((Fets.word & FET_UP) ? 100 : 0);
   vSetDuty6B((Fets.word & FET_DOWN) ? 100 : 0);
   vSetStatus7C((Fets.word & FET_RIGHT) ? 1 : 0);
   vSetDuty7B((Fets.word & FET_LEFT) ? 100 : 0);
   vSetStatus9C((Fets.word & FET_BRAKES) ? 1 : 0);
   vSetStatus8A((Fets.word & FET_MCE) ? 1 : 0);
   vSetStatus8B((Fets.word & FET_HORN) ? 1 : 0);
   vSetStatus8C((Fets.word & FET_PARALLEL) ? 1 : 0);
   vSetStatus3A((Fets.word & FET_SPARE) ? 1 : 0);
   vSetStatus9B((Fets.word & FET_ALARM) ? 1 : 0);
   vSetStatus2A((ALARM_Data2.fGround) ? 1 : 0);//ALARM_Data.fGround2
}


/*******************************************************************************
 *
 * PROCEDURE:  FET_Init()
 *
 * DESCRIPTION: It is preset the FET serial regiser to all zeros( OFF state)
 *              before enable the register outputs.
 *
 * VARIABLE NAME  R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 * FetsLocal        R/W
 * Fets             R
 ******************************************************************************/

void
FET_Init(void)
{
   Fets.word = 0;
   FET_Update();
}



/*******************************************************************************
 *
 * PROCEDURE:  FET_Check()
 *
 * DESCRIPTION: It tests the FET load current to be in a range then FET is active.
 *              The range is defined by short and open current. The FER_Check()
 *              function is invoked every system cycle ( 10 millisecond) to set
 *              new channel and check the previously set one. The channel preset due
 *              FET current stablization time that is about 2 milliseconds.
 *              FET error is accumulated for  time bCoilFaultDetectionPeriod.
 *
 * VARIABLE NAME  R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 * FetsLocal        R/W
 * Fets             R
 ******************************************************************************/

void
FET_Check(void)
{
   UINT8 bIndex;

   bIndex = FET_Data.bFetToCheck;

   // if the FET is OFF
   if(!(Fets.word & FET_CheckTable[bIndex].wMask))
   {
      // save FET status
      FET_Data.bOffStatus[bIndex] = FET_CheckTable[bIndex].pfSSRStatus();
      // clear error count
      FET_Data.bErrorCount[bIndex] = 0;
   }
   // if the FET is ON
   else
   {
      // if FET status is reversed or open fault is detected
      if((FET_CheckTable[bIndex].pfSSRStatus() != FET_Data.bOffStatus[bIndex]) || FET_Data.u8DualOpenStatus[bIndex])
      {
         // error count
         FET_Data.bErrorCount[bIndex]++;
         // trigger error
         if ( FET_Data.bErrorCount[bIndex] > ERROR_LATCH)
         {
            FET_Data.bErrorCount[bIndex] = ERROR_LATCH;
            // Another special case, if 0807 and 58 change name to 82
            if(lift_setup.bLiftType == ELEC3  && FET_CheckTable[bIndex].bErrorCode  == FAULT_BRAKE_COIL)
            {
               NVM_SaveFault(FAULT_LEFT_BRAKE_COIL);                 // ERROR 82
               // set fault word 2
               FaultWord2 |= 1 << 6;
            }
            else
            {
               NVM_SaveFault(FET_CheckTable[bIndex].bErrorCode);
               // set fault word 2
               FaultWord2 |= 1 << bIndex;
            }
            // set fault flag
            LIFT_Data.fMotorFault = 1;
         }
      }
      // if FET status is right
      else
      {
         if ( FET_Data.bErrorCount[bIndex] > 0 )
         {
            FET_Data.bErrorCount[bIndex]--;
         }
      }
   }

   // mask error
   if(lift_setup.bLiftType == ELEC1 || lift_setup.bLiftType == ELEC3 /*|| lift_setup.bLiftType == ELEC2*/)
   {
      if(FET_CheckTable[bIndex].wMask & (FET_FORWARD | FET_REVERSE | FET_MCE2))
      {
         FET_Data.bErrorCount[bIndex] = 0;
      }
   }
   if(SMALL_SLAB == lift_setup.bLiftType /*|| lift_setup.bLiftType == ELEC2*/)
   {
      if(FET_CheckTable[bIndex].wMask & FET_BRAKES)
      {
         FET_Data.bErrorCount[bIndex] = 0;
      }
   }

   // turn to next valve
   FET_Data.bFetToCheck++;
   if(FET_Data.bFetToCheck >= NUMBER_OF_FETS_TO_CHECK)
   {
      FET_Data.bFetToCheck = 0;
   }

   // check brake error
   if(lift_setup.bLiftType == ELEC1)
   {
      if(!(Fets.word & FET_BRAKES) && (LEFT_BRAKE  || RIGHT_BRAKE))
      {
         if(!FET_Data.bErrorCountBrake)
         {
            NVM_SaveFault((LEFT_BRAKE) ? FAULT_LEFT_BRAKE_COIL : FAULT_RIGHT_BRAKE_COIL);
            LIFT_Data.fMotorFault = 1;
         }

         FET_Data.bErrorCountBrake--;
      }
      else { FET_Data.bErrorCountBrake = 15; }
   }
   if(FaultWord2 == 0x1)      //FAULT_FORWARD_COIL
   {
      unCanFault2.word |= 0x0001;
   }
   else if(FaultWord2 == 0x2)  //FAULT_REVERSE_COIL
   {
      unCanFault2.word |= 0x0002;
   }
   else if(FaultWord2 == 0x4)   //FAULT_UP_COIL
   {
    unCanFault2.word |= 0x0004;
   }
   else if(FaultWord2 == 0x8)    //FAULT_DOWN_COIL
   {
    unCanFault2.word |= 0x0008;
   }
   else if(FaultWord2 == 0x10)    //FAULT_RIGHT_COIL
   {
    unCanFault2.word |= 0x0020;
   }
   else if(FaultWord2 == 0x20)     //FAULT_LEFT_COIL
   {
    unCanFault2.word |= 0x0040;
   }
   else if(FaultWord2 == 0x40)      //FAULT_BRAKE_COIL
   {
    unCanFault2.word |= 0x0010;
   }
}

/*******************************************************************************
 *
 * PROCEDURE:  vCheckDualOpenCircuit()
 *
 * DESCRIPTION: This function check FET open fault when machine power-on. It turn
 *              on FET of each pair channel for 10ms and check if any FET is open.
 *
 ******************************************************************************/
void vCheckDualOpenCircuit(void)
{
   static UINT8 u8_check_step = 0;

   switch(u8_check_step)
   {
      case 0:
         vSetDuty7A(100);   //forward
         vSetDuty6A(100);  //up
         vSetStatus7C(1);  //right
         u8_check_step++;
         break;
      case 1:
         FET_Data.bOffStatus[0] = FET_CheckTable[0].pfSSRStatus();
         FET_Data.bOffStatus[2] = FET_CheckTable[2].pfSSRStatus();
         FET_Data.bOffStatus[4] = FET_CheckTable[4].pfSSRStatus();
         vSetDuty7A(0); //forward
         vSetDuty6A(0); //up
         vSetStatus7C(0);  //right
         u8_check_step++;
         break;
      case 2:
         vSetDuty6C(100);  //reverse
         //vSetDuty6B(100);  //down
         vSetDuty7B(100); //left
         u8_check_step++;
         break;
      case 3:
         FET_Data.bOffStatus[1] = FET_CheckTable[1].pfSSRStatus();
         FET_Data.bOffStatus[3] = FET_CheckTable[3].pfSSRStatus();
         FET_Data.bOffStatus[5] = FET_CheckTable[5].pfSSRStatus();
         vSetDuty6C(0);  //reverse
         vSetDuty6B(0);  //down
         vSetDuty7B(0); //left

         if((!FET_Data.bOffStatus[0]) && (!FET_Data.bOffStatus[1]))
         {
            FET_Data.u8DualOpenStatus[0] = 1;
            FET_Data.u8DualOpenStatus[1] = 1;
         }
         if((!FET_Data.bOffStatus[2]) && (!FET_Data.bOffStatus[3]))
         {
           // FET_Data.u8DualOpenStatus[2] = 1;
           // FET_Data.u8DualOpenStatus[3] = 1;
         }
         if((!FET_Data.bOffStatus[4]) && (!FET_Data.bOffStatus[5]))
         {
            FET_Data.u8DualOpenStatus[4] = 1;
            FET_Data.u8DualOpenStatus[5] = 1;
         }
         u8_check_step++;
         break;
      default:
         break;
   }

}

/*************************************************************************//**
* @ingroup fault
* @brief   check OUTDOOR_LIMIT switch failure
* @note    check in operation state
* @param   none
* @return  none
*****************************************************************************/
void vCheckOutDoorLimitSwitchFault(void)
{
	static UINT16 u16_ai_angle_dead = 10;
	
	if(lift_options.fBattery_drain == 1 && !lift_options.fKorea_option)
	{
		if(OUTDOOR_LIMIT == FALSE && 
		  (ui_Measured_Scissor_Angle_Main > NVM_TripAngleState.anData[OUTDOOR_LIMIT_ANGLE] + u16_ai_angle_dead))
		{
			MAIN_Data.bOutDoorLSFault = TRUE;
			NVM_SaveFault(FAULT_OUTDOOR_LS_FAILURE);
			//unCanFault1.word |= 0x8000;
		}

		if(OUTDOOR_LIMIT == TRUE && 
		  (ui_Measured_Scissor_Angle_Main < NVM_TripAngleState.anData[OUTDOOR_LIMIT_ANGLE] - u16_ai_angle_dead + 4))
		{
			MAIN_Data.bOutDoorLSFault = TRUE;
			NVM_SaveFault(FAULT_OUTDOOR_LS_FAILURE);
			//unCanFault1.word |= 0x8000;
		}		
	}   
}








